﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Galaktika.BI.Silverlight.Controls.PivotGrid.Data.Providers;

namespace Galaktika.BI.Silverlight.Controls.PivotGrid.Controls
{
    public class PivotGridPanel : Panel
    {
        public readonly PivotDataControl SpanPivotGrid = null;

        public PivotGridPanel(PivotDataControl pivotGrid)
            : base()
        {
            if (pivotGrid == null)
            {
                throw new ArgumentNullException("pivotGrid");
            }
            SpanPivotGrid = pivotGrid;
            
            ColumnsControl = new ColumnsAreaControl(this);
            RowsControl = new RowsAreaControl(this);
            CellsControl = new CellsAreaControl(this);

            CellsControl.FocusedCellChanged += new FocusedCellChangedEventHandler(CellsControl_FocusedCellChanged);

            Children.Add(CellsControl);
            Children.Add(ColumnsControl);
            Children.Add(RowsControl);
            Children.Add(CrossRectangle);
        }

        void CellsControl_FocusedCellChanged(object sender, FocusedCellChangedEventArgs e)
        {
            if (e.NewFocusedCell != null)
            {
                NavigateTo(e.NewFocusedCell);
            }
        }

        /// <summary>
        /// Позицирнирует на указанную ячейку. Если ячейка невидима, то отображается начиная с верхнего левого угла
        /// </summary>
        /// <param name="cell"></param>
        private void NavigateTo(CellControl cell)
        {
            ScrollViewer scroller = this.Parent as ScrollViewer;
            if (scroller != null && cell != null)
            {
                Point cell_Pos = CellsControl.GetCellPosition(cell);

                Size visibleCellsSize = new Size(scroller.ViewportWidth - RowsControl.ActualWidth, scroller.ViewportHeight - ColumnsControl.ActualHeight);

                bool scrolled = false;

                // Если правая граница ечейки не помещается в видимую область
                if ((cell_Pos.X + cell.ActualWidth) > (scroller.HorizontalOffset + visibleCellsSize.Width))
                {
                    // Какая часть ячейки справа не влезла для отображения 
                    double delta = (cell_Pos.X + cell.ActualWidth) - (scroller.HorizontalOffset + visibleCellsSize.Width);
                    // Устанавливаем новой значение для скролла с учетом максимально возможного
                    double newValue = scroller.HorizontalOffset + delta;
                    // Следует учесть что при попытке отобразить правую границу ячейки ее левая граница может стать невидимой, 
                    // что в нашем случае недопустимо. Поэтому данное рассчетное значение корректируем чтобы левая часть стала видимой
                    if (cell_Pos.X < newValue)
                        newValue = cell_Pos.X;
                    scroller.ScrollToHorizontalOffset(newValue);
                    scrolled = true;
                }
                else
                {
                    // Проверяем чтобы ячейка (левая координата) была видимой
                    // Если левая координата ячейки меньше значения скролла, то надо путем изменения значения скролла сделать ее видимой
                    if (cell_Pos.X < scroller.HorizontalOffset)
                    {
                        scroller.ScrollToHorizontalOffset(cell_Pos.X);
                        scrolled = true;
                    }
                }

                // Проверяем чтобы ячейка (верхняя координата) была видимой
                // Если верхняя координата ячейки меньше значения скролла, то надо путем изменения значения скролла сделать ее видимой
                if (cell_Pos.Y < scroller.VerticalOffset)
                {
                    scroller.ScrollToVerticalOffset(cell_Pos.Y);
                    scrolled = true;
                }
                else
                {
                    // Если верхняя кордината больше чем нижняя граница видимой области
                    if ((cell_Pos.Y + cell.ActualHeight) > (scroller.VerticalOffset + visibleCellsSize.Height))
                    {
                        // Какая часть ячейки справа не влезла для отображения 
                        double delta = (cell_Pos.Y + cell.ActualHeight) - (scroller.VerticalOffset + visibleCellsSize.Height);
                        // Устанавливаем новой значение для скролла с учетом максимально возможного
                        double newValue = scroller.VerticalOffset + delta;
                        // Следует учесть что при попытке отобразить нижнюю границу ячейки ее верхняя граница может стать невидимой, 
                        // что в нашем случае недопустимо. Поэтому данное рассчетное значение корректируем чтобы верхняя часть стала видимой
                        if (newValue < scroller.VerticalOffset)
                            newValue = scroller.VerticalOffset;

                        scroller.ScrollToVerticalOffset(newValue);
                        scrolled = true;
                    }
                }

                if (scrolled)
                    this.InvalidateArrange();
            }
        }

        Rectangle m_CrossRectangle = null;
        public Rectangle CrossRectangle
        {
            get
            {
                if (m_CrossRectangle == null)
                {
                    m_CrossRectangle = new Rectangle();
                    // TODO: Надо взять фон сводной таблицы
                    m_CrossRectangle.Fill = new SolidColorBrush(Colors.White);
                }
                return m_CrossRectangle;
            }
        }

        public readonly MembersAreaContol ColumnsControl = null;
        public readonly MembersAreaContol RowsControl = null;
        public readonly CellsAreaControl CellsControl = null;

        CellSetDataProvider m_CellSetProvider = null;
        public CellSetDataProvider CellSetProvider
        {
            get {
                return m_CellSetProvider;
            }
        }

        public void Initialize(CellSetDataProvider provider)
        {
            m_CellSetProvider = provider;
            if (provider != null)
            {
                ColumnsControl.Initialize(provider.Columns);
                RowsControl.Initialize(provider.Rows);
                CellsControl.Intialize(provider);
            }
        }

        protected override Size MeasureOverride(Size availableSize)
        {
            Size resultSize = new Size(0, 0);

            foreach (UIElement child in Children)
            {
                child.Measure(availableSize);
                //resultSize.Width = Math.Max(resultSize.Width,
                //    child.DesiredSize.Width);
                //resultSize.Height = Math.Max(resultSize.Height,
                //    child.DesiredSize.Height);
            }

            resultSize.Width = RowsControl.DesiredSize.Width + CellsControl.DesiredSize.Width;
            resultSize.Height = ColumnsControl.DesiredSize.Height + CellsControl.DesiredSize.Height;

            resultSize.Width =
                double.IsPositiveInfinity(availableSize.Width) ?
                resultSize.Width : availableSize.Width;

            resultSize.Height =
                double.IsPositiveInfinity(availableSize.Height) ?
                resultSize.Height : availableSize.Height;

            return resultSize;
        }

        protected override Size ArrangeOverride(Size finalSize)
        {
            ScrollViewer scroller = this.Parent as ScrollViewer;
            if (scroller != null)
            {
                RowsControl.Arrange(
                    new Rect(scroller.HorizontalOffset, ColumnsControl.DesiredSize.Height, RowsControl.DesiredSize.Width, RowsControl.DesiredSize.Height));

                ColumnsControl.Arrange(
                    new Rect(RowsControl.DesiredSize.Width, scroller.VerticalOffset, ColumnsControl.DesiredSize.Width, ColumnsControl.DesiredSize.Height));

                CellsControl.Arrange(
                    new Rect(RowsControl.DesiredSize.Width, ColumnsControl.DesiredSize.Height, CellsControl.DesiredSize.Width, CellsControl.DesiredSize.Height));

                CrossRectangle.Arrange(
                    new Rect(scroller.HorizontalOffset, scroller.VerticalOffset, RowsControl.DesiredSize.Width, ColumnsControl.DesiredSize.Height));
            }
            else
            {
                foreach (UIElement child in Children)
                {
                    child.Arrange(new Rect(0, 0, child.DesiredSize.Width - 1,
                      child.DesiredSize.Height - 1));
                }
            }

            return finalSize;
        }

        public Rect CellsAreaBounds
        {
            get {
                ScrollViewer scroller = this.Parent as ScrollViewer;
                if (scroller != null)
                {
                    // Размер видимой области ячеек - это размер порта вывода(сюды уже учитываются размеры самих скролбаров) скроллера минус размер области строк и столбцов
                    return (new Rect(scroller.HorizontalOffset, scroller.VerticalOffset, CellsAreaSize.Width, CellsAreaSize.Height));
                }
                else
                    return Rect.Empty;
            }
        }

        private Size CellsAreaSize
        {
            get
            {
                ScrollViewer scroller = this.Parent as ScrollViewer;
                if (scroller != null)
                {
                    // Размер видимой области ячеек - это размер порта вывода(сюды уже учитываются размеры самих скролбаров) скроллера минус размер области строк и столбцов
                    return new Size(scroller.ViewportWidth - RowsControl.ActualWidth, scroller.ViewportHeight - ColumnsControl.ActualHeight);
                }
                else
                    return Size.Empty;
            }
        }

        public void ScrollVerticalOffsetTo(double newValue)
        {
            ScrollViewer scroller = this.Parent as ScrollViewer;
            if (scroller != null)
            {
                newValue = Math.Max(0, newValue);
                if (scroller.VerticalOffset != newValue)
                {
                    scroller.ScrollToVerticalOffset(newValue);
                    scroller.UpdateLayout();
                }
            }
        }

        public void PageUp()
        {
            ScrollViewer scroller = this.Parent as ScrollViewer;
            if (scroller != null)
            {

                double newValue = scroller.VerticalOffset - CellsAreaSize.Height;

                newValue = Math.Max(0, newValue);
                if (scroller.VerticalOffset != newValue)
                {
                    scroller.ScrollToVerticalOffset(newValue);
                    scroller.UpdateLayout();
                }
            }
        }
    }
}
